#include "watchpoint.h"
#include "expr.h"
#include <stdlib.h>

#define NR_WP 32

static WP wp_pool[NR_WP];
static WP *head, *free_;

void init_wp_pool() {
	int i;
	for(i = 0; i < NR_WP; i ++) {
		wp_pool[i].NO = i;
		wp_pool[i].next = &wp_pool[i + 1];
	}
	wp_pool[NR_WP - 1].next = NULL;

	head = NULL;
	free_ = wp_pool;
}

/* TODO: Implement the functionality of watchpoint */


static WP* new_wp()
{
	assert(free_!=NULL);
	WP* wp=free_;
	free_=free_->next;
	return wp;
}

static void free_wp(WP* wp)
{
	assert(wp >= wp_pool && wp < wp_pool + NR_WP);
	free(wp->expr);
	wp->next=free_;
	free_=wp;
}

int set_watchpoint(char* e)
{
	uint32_t val;
	bool success;
	val=expr(e,&success);
	if(!success) return -1;

	WP* wp=new_wp();
	wp->expr=strdup(e);
	wp->pre_val=val;

	wp->next=head;
	head=wp;

	return wp->NO;
}

bool delete_watchpoint(int NO)
{
	WP *p1,*p2=NULL;
	for(p1=head;p1!=NULL;p1=p1->next)
	{
		if(p1->NO==NO)
			break;
		p2=p1;
	}
	if(p1==NULL)
		return false;
	if(p2==NULL)
		head=p1->next;
	else
		p2->next=p1->next;

	free_wp(p1);
	return true;
}

void list_watchpoint()
{
	if(head==NULL)
	{
		printf("No watchpoints!\n");
		return ;
	}
	printf("%8s\t%8s\t%8s\n","NO","Expression","Value");
	WP * wp;
	for(wp=head;wp!=NULL;wp=wp->next)
	{
		printf("%8d\t%s\t0x%08x\n",wp->NO,wp->expr,wp->pre_val);
	}
}


WP* scan_watchpoint()
{
	WP* wp;
	for(wp=head;wp!=NULL;wp=wp->next)
	{
		bool success;
		wp->new_val=expr(wp->expr,&success);
		if(wp->pre_val!=wp->new_val)
		return wp;
	}
	return NULL;
}